package com.walterlife.dp;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.sql.Connection;
import java.util.List;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

import com.walterlife.dp.AdapterDP.SocketAdapter;
import com.walterlife.dp.AdapterDP.SocketClassAdapterImpl;
import com.walterlife.dp.AdapterDP.Volt;
import com.walterlife.dp.BridgeDP.GreenColor;
import com.walterlife.dp.BridgeDP.Pantagon;
import com.walterlife.dp.BridgeDP.RedColor;
import com.walterlife.dp.BridgeDP.TriAngle;
import com.walterlife.dp.BuilderDP.Computer;
import com.walterlife.dp.CompositeDP.Circle;
import com.walterlife.dp.CompositeDP.Drawing;
import com.walterlife.dp.CompositeDP.Shape;
import com.walterlife.dp.CompositeDP.Triangle;
import com.walterlife.dp.DecoratorDP.BasicCar;
import com.walterlife.dp.DecoratorDP.Car;
import com.walterlife.dp.DecoratorDP.LuxuryCar;
import com.walterlife.dp.DecoratorDP.SportsCar;
import com.walterlife.dp.FacadeDP.HelperFacade;
import com.walterlife.dp.FacadeDP.MySqlHelper;
import com.walterlife.dp.FacadeDP.OracleHelper;
import com.walterlife.dp.FlyweightDP.DrawClient;
import com.walterlife.dp.ProtoTypeDP.Employees;
import com.walterlife.dp.ProxyDP.CommandExecuterProxy;
import com.walterlife.dp.SingletonDP.EnumSingleton;
import com.walterlife.dp.SingletonDP.SerializedSingleton;

public class App {
    static Logger logger = Logger.getLogger(App.class.getName());

    public static void main( String[] args ) throws FileNotFoundException, IOException, ClassNotFoundException {
        logger.setLevel((Level)(Level.DEBUG));
        //testSingletonDP();
        //testSerializedSingleton();
        //testAdapter();
        //testBuilder();
        //testComposite();
        //testProxy();
        //testFlyweight();
        //testFacade();
        //testBridge();
        testDecarator();
    }

    public static void testDecarator() {
        Car sportsCar = new SportsCar(new BasicCar());
        sportsCar.assemble();

        Car sportsLuxuryCar = new SportsCar(new LuxuryCar(new BasicCar()));
        sportsLuxuryCar.assemble();
    } 

    public static void testBridge() {
        TriAngle triangle = new TriAngle(new RedColor());
        triangle.applyColor();

        Pantagon pantagon = new Pantagon(new GreenColor());
        pantagon.applyColor();
    } 

    public static void testFacade() {
        String tbName = "tb_student";

        //generating MySql HTML report and Oracle PDF report without using Facade
        System.out.printf("--------------generate report without Facade---------\n");
        Connection con = MySqlHelper.getMysqlDBConnection();
        MySqlHelper mySqlHelper = new MySqlHelper();
        mySqlHelper.generateMySqlHTMLReport(tbName, con);
         
        Connection con1 = OracleHelper.getOracleDBConnection();
        OracleHelper oracleHelper = new OracleHelper();
        oracleHelper.generateOraclePDFReport(tbName, con1);

        System.out.printf("--------------generate report with Facade---------\n");
        HelperFacade helpFacade = new HelperFacade();
        helpFacade.generateReport(HelperFacade.DBTypes.MYSQL, HelperFacade.ReportTypes.PDF, tbName);
        helpFacade.generateReport(HelperFacade.DBTypes.MYSQL, HelperFacade.ReportTypes.HTML, tbName);
        helpFacade.generateReport(HelperFacade.DBTypes.ORACLE, HelperFacade.ReportTypes.PDF, tbName);
        helpFacade.generateReport(HelperFacade.DBTypes.ORACLE, HelperFacade.ReportTypes.HTML, tbName);
    } 

    public static void testFlyweight() {
        DrawClient client = new DrawClient(500, 600);
    } 

    public static void testProxy() {
        CommandExecuterProxy commondExecuterProxy = new CommandExecuterProxy("nadmin", "admin");
        try {
            commondExecuterProxy.runCommand("ls -lrt"); 
            commondExecuterProxy.runCommand("rm tt"); 
        } catch(Exception e) {
            logger.error("Exception message: " + e.getMessage()); 
        }
    } 

    public static void testComposite() {
        Drawing drawing = new Drawing("Drawing");

        Shape cir = new Circle("Circle");
        Shape tri1 = new Triangle("Triangle");
        Shape tri2 = new Triangle("Triangle");
        
        drawing.addShapes(cir);
        drawing.addShapes(tri1);
        drawing.addShapes(tri2);

        drawing.draw("RED");

        drawing.clear();

        drawing.addShapes(cir);
        drawing.addShapes(tri1);

        drawing.draw("GREEN");
    } 

    public static void testBuilder() {
        Computer computer = new Computer.ComputerBuilder("500 GB", "2 GB")
            .setGraphicsCardEnabled(true)
            .setBuletoothEnabled(true)
            .build();

        System.out.printf("build computer result: %s\n", computer.toString());
    } 

    public static Volt getVolt(SocketAdapter adapter, int v) {
        Volt volt = null;
        if(v <= 0) {
            logger.error("param v: " + v + " is not valid !!!");
        } else if(adapter == null) {
            logger.error("param adapter is not null !!!");
        } else {
            switch(v) {
                case 3:
                    volt = adapter.get3Volt();
                    break;
                case 12:
                    volt = adapter.get12Volt();
                    break;
                case 220:
                    volt = adapter.get220Volt();
                    break;
                default:
                    volt = adapter.get220Volt();
                    break;
            } 
        } 
        return volt;
    } 

    public static void testAdapter() {
        SocketClassAdapterImpl socketAdapter = new SocketClassAdapterImpl();
        Volt v3 = getVolt(socketAdapter, 3);
        Volt v12 = getVolt(socketAdapter, 12);
        Volt v220 = getVolt(socketAdapter, 220);

        if(v3 != null && v12 != null && v220 != null) {
            System.out.printf("v3 volts: %d\nv12 volts: %d\nv220 volts: %d\n", v3.getVolts(), v12.getVolts(), v220.getVolts());
        } else {
            System.out.printf("v3 null: %s\nv12 null: %s\nv220 null: %s\n", 
                    ((v3 != null) ? "no" : "yes"),
                    ((v12 != null) ? "no" : "yes"),
                    ((v220 != null) ? "no" : "yes"));
        } 
    } 

    public static void testSerializedSingleton() throws FileNotFoundException, IOException, ClassNotFoundException {
        SerializedSingleton instanceOne = SerializedSingleton.getInstance();
        ObjectOutput out = new ObjectOutputStream(new FileOutputStream("test_serialized"));

        out.writeObject(instanceOne);
        out.close();

        ObjectInput in = new ObjectInputStream(new FileInputStream("test_serialized"));
        SerializedSingleton instanceTwo = (SerializedSingleton)in.readObject();
        in.close();

        System.out.printf("Instance One hashCode: %d\n", instanceOne.hashCode());
        System.out.printf("Instance Two hashCode: %d\n", instanceTwo.hashCode());

    } 

    public static void testSingletonDP() {

        System.out.printf("Instance: %s\n", EnumSingleton.INSTANCE);

        for(EnumSingleton instance: EnumSingleton.values()) {
            System.out.printf("Instance: %s\n", instance);
        }
    } 
    public static void testProtoTypeDP() {
        Employees emp = new Employees();
        emp.loadData();
        logger.info("emp emps: " + emp.getEmpList());

        Employees empNew;
        try {
            empNew = (Employees) emp.clone();
            if(empNew != null) {
                List<String> list = empNew.getEmpList();
                if(list != null) {
                    list.add("hehe");
                } else {
                    logger.error("empNew-list is null!!!");
                } 
                logger.info("empNew emps: " + empNew.getEmpList());
            } else {
                logger.error("empNew is null!!!");
            } 

            Employees empNew1 = (Employees)emp.clone();

            if(empNew1 != null) {
                List<String> list1 = empNew1.getEmpList();
                if(list1 != null) {
                    if(list1.indexOf("hello") != -1) {
                        list1.remove("hello");
                    } else {
                        logger.warn("key hello not exist!!");
                    } 
                    logger.info("empNew1 emps: " + empNew1.getEmpList());
                } else {
                    logger.error("empNew1-list is null!!!");
                } 
            } else {
                logger.error("empNew1 is null!!!");
            } 
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }

    } 
}
